package com.sh.business.config;

import com.sh.common.core.enums.MqQueueEnum;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

/**
 * 消息队列相关配置
 * @author dongGe_zzz
 * @date 2023-08-14 11:08
 */
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
@Slf4j
@Configuration
public class RabbitMqConfig {

    private final RabbitTemplate rabbitTemplate;

    /**
     * 订单消息实际消费队列所绑定的交换机
     */
    @Bean
    DirectExchange callbackDirectExchange() {
        return ExchangeBuilder
            .directExchange(MqQueueEnum.CALLBACK_DIRECT.getExchange())
            .durable(true)
            .build();
    }

    @Bean
    DirectExchange ttlDirectExchange() {
        return ExchangeBuilder
            .directExchange(MqQueueEnum.TTL_DIRECT.getExchange())
            .durable(true)
            .delayed()
            .build();
    }

    @Bean
    DirectExchange ttlDailyDynamicsDirectExchange() {
        return ExchangeBuilder
            .directExchange(MqQueueEnum.TTL_DAILY_DYNAMICS_DIRECT.getExchange())
            .durable(true)
            .delayed()
            .build();
    }

    @Bean
    DirectExchange ttlDailyDynamicsOutDirectExchange() {
        return ExchangeBuilder
            .directExchange(MqQueueEnum.TTL_DAILY_DYNAMICS_OUT_DIRECT.getExchange())
            .durable(true)
            .delayed()
            .build();
    }

    /**
     * 异步消息
     */
    @Bean
    public Queue callbackDirectQueue() {
        return new Queue(MqQueueEnum.CALLBACK_DIRECT.getQueue());
    }

    /**
     * 延迟消息
     */
    @Bean
    public Queue ttlDirectQueue() {
        return new Queue(MqQueueEnum.TTL_DIRECT.getQueue());
    }

    @Bean
    public Queue ttlDailyDynamicsDirectQueue() {
        return new Queue(MqQueueEnum.TTL_DAILY_DYNAMICS_DIRECT.getQueue());
    }

    @Bean
    public Queue ttlDailyDynamicsOutDirectQueue() {
        return new Queue(MqQueueEnum.TTL_DAILY_DYNAMICS_OUT_DIRECT.getQueue());
    }

    /**
     * 将订单队列绑定到交换机
     */
    @Bean
    Binding callbackDirectBinding(DirectExchange callbackDirectExchange, Queue callbackDirectQueue){
        return BindingBuilder
            .bind(callbackDirectQueue)
            .to(callbackDirectExchange)
            .with(MqQueueEnum.CALLBACK_DIRECT.getRouteKey());
    }

    /**
     * 将订单超时未支付延迟队列绑定到交换机
     */
    @Bean
    Binding ttlDirectBinding(DirectExchange ttlDirectExchange,Queue ttlDirectQueue){
        return BindingBuilder
            .bind(ttlDirectQueue)
            .to(ttlDirectExchange)
            .with(MqQueueEnum.TTL_DIRECT.getRouteKey());
    }

    @Bean
    Binding ttlDailyDynamicsDirectBinding(DirectExchange ttlDailyDynamicsDirectExchange, Queue ttlDailyDynamicsDirectQueue){
        return BindingBuilder
            .bind(ttlDailyDynamicsDirectQueue)
            .to(ttlDailyDynamicsDirectExchange)
            .with(MqQueueEnum.TTL_DAILY_DYNAMICS_DIRECT.getRouteKey());
    }

    @Bean
    Binding ttlDailyDynamicsOutDirectBinding(DirectExchange ttlDailyDynamicsOutDirectExchange, Queue ttlDailyDynamicsOutDirectQueue){
        return BindingBuilder
            .bind(ttlDailyDynamicsOutDirectQueue)
            .to(ttlDailyDynamicsOutDirectExchange)
            .with(MqQueueEnum.TTL_DAILY_DYNAMICS_OUT_DIRECT.getRouteKey());
    }


    @PostConstruct
    public void initRabbitTemplate(){
        // 设置确认回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {

            @Override
            public void confirm(CorrelationData correlationData, boolean b, String s) {
                log.info("设置发送 correlationData:{}, b:{}, s:{}", correlationData, b, s);
            }
        });

        // 设置消息抵达队列的确认回调
        rabbitTemplate.setReturnsCallback(returnedMessage -> log.info("确认送达 message:{}", returnedMessage.getReplyCode()));
    }
}
